package com.thientan.service

import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.ss.usermodel.Cell
import org.apache.poi.ss.usermodel.Row
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.xssf.usermodel.XSSFWorkbook

import com.thientan.export.ExportRequest
import com.thientan.model.HopDong
import com.thientan.model.ThongKePhieuThu
import com.thientan.utils.Constants

class PhieuThuService extends AbstractService {
	ThongKePhieuThuService thongKePhieuThuService
	
	@Override
	protected Long[] getColWidth() {
		return [80, 70, 130, 70, 150] as Long[]
	}

	@Override
	protected String[] getColTitles() {
		return ['Ngày thu', 'Số tiền', 'Thu ngân', 'Loại chi tiết', 'Người nhập'] as String[]
	}

	@Override
	protected String[] getColNames() {
		return ['ngayLapText', 'soTien', 'tenThuNgan', 'loaiChiTiet', 'tenNvNhap'] as String[]
	}

	@Override
	@SuppressWarnings("rawtypes")
	protected Class<?>[] getExportColType() {
		return [String.class, BigDecimal.class, String.class, String.class, String.class] as Class<?>[]
	}

	@Override
	void prepareParametersBeforeExport(ExportRequest er){
		er.addParameter("maHd", this.exportData?.maHd)
		er.addParameter("lastUpdatedUser", this.exportData?.lastUpdatedUser)
		er.addParameter("lastUpdatedDate", this.exportData?.lastUpdatedDate)
	}

	/**
	 * Perform "import" action which data retrieved from Excel file.
	 * @param importFile File to be imported
	 * @param extension Format of file (XLS or XLSX)
	 * @return
	 */
	Map processImport(File importFile, String extension) {
		log.info("Starting import data from file")
		Sheet sheet = null
		InputStream myxls = new FileInputStream(importFile)
		if (extension == Constants.XLS_FORMAT) {
			sheet = new HSSFWorkbook(myxls).getSheetAt(0)
		} else {
			sheet = new XSSFWorkbook(myxls).getSheetAt(0)
		}

		List emptyMaHds = []
		List emptySoTiens = []
		List invalidSoTiens = []
		List exceedAmountHds = []
		Map hdInfo = [:]
		for (int i = 1; i <= sheet.physicalNumberOfRows; i++) {
			Row row = sheet.getRow(i)
			if (isBlankRow(row)) { // If exist any blank row in file, break the import process.
				break
			} else {
				Cell maHdCell = row.getCell(0)
				Cell soTienCell = row.getCell(1)
				if (maHdCell == null || maHdCell.stringCellValue == null || maHdCell.stringCellValue == "") {
					emptyMaHds << i
					continue
				}
				if (!soTienCell) {
					emptySoTiens << i
					continue
				}
				Double soTien
				if (soTienCell.cellType == Cell.CELL_TYPE_STRING) {
					try {
						soTien = Double.valueOf(soTienCell.stringCellValue)
					} catch (Exception e) {
						invalidSoTiens << i
						continue
					}
				} else if (soTienCell.cellType == Cell.CELL_TYPE_NUMERIC) {
					soTien = soTienCell.numericCellValue
				}
				hdInfo.put(maHdCell.stringCellValue, soTien)
			}
		}

		List<HopDong> updatedHds = HopDong.findAllByMaHdInList(hdInfo.keySet())
		long numOfUpdate = 0
		updatedHds.each {
			int result = it.updateTraGop(hdInfo.get(it.maHd))
			if (result == 1) {
				exceedAmountHds << it.maHd
			} else {
				++numOfUpdate
				it.save()
			}
		}

		log.info("Finish import data from file")
		return ["updated" : numOfUpdate, 
				"emptyMaHds" : emptyMaHds, 
				"emptySoTiens" : emptySoTiens, 
				"exceedAmountHds" : exceedAmountHds,
				"invalidSoTiens" : invalidSoTiens]
	}
	
	/**
	 * Save PhieuThu (based on cases: normal NhapPhieu, NhapPhieu to KetThuc, TraHang, DenHang and KhoThu),
	 * then re-calculate statistic of PhieuThu.
	 * @param hd The HopDong which is indicated in PhieuThu
	 * @return The saved HopDong
	 */
	HopDong savePhieuThuAndReCalculateThongKePhieuThu(HopDong hd, Date previousDaGiaoPhieu) {
		ThongKePhieuThu tkPt = thongKePhieuThuService.fetchOrCreateThongKePt()
		HopDong savedHopDong = hd.save()
		if (!savedHopDong) {
			return hd
		}
		thongKePhieuThuService.updateThongKePhieuThu(tkPt, hd, 1 /*numHd*/, previousDaGiaoPhieu)
		if (!tkPt.errors.hasErrors()) {
			return hd
		} else {
			log.error("Unable to update ThongKePhieuThu when input PhieuThu: ${tkPt.errors}")
			throw new Exception("default.thientan.messages.updateTkPtFailed")
		}
	}
	
	/**
	 * Check whether if an Excel row is blank (all cells in row are blank).
	 * @param row
	 * @return
	 */
	private boolean isBlankRow(Row row) {
		if (row == null) {
			return true
		}
		for (int i = 0; i < row.physicalNumberOfCells; i++) {
			if (!isBlankCell(row.getCell(i))) {
				return false
			}
		}
		return true
	}
	
	/**
	 * Check whether if an Excel cell is blank (null, blank or just contains spaces).
	 * @param cell
	 * @return
	 */
	private boolean isBlankCell(Cell cell) {
		// In case of cell is null or blank, we convert it to null for checking later.
		// We cannot detect the exact null or blank value of a cell when it have no data inside
		// because it depends on user action to that cell (select all cell's text and press Delete,
		// select all cell's text and press Ctrl+X to cut it out, press BackSpace, etc.)
		if (cell == null || cell.cellType == Cell.CELL_TYPE_BLANK) {
			return true
		} else if (cell.cellType == Cell.CELL_TYPE_NUMERIC) {
			return cell.numericCellValue.toString().trim() == ""
		} else {
			return cell.stringCellValue.trim() == ""
		}
	}
}
